#include <stdio.h>
#include <inttypes.h>
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "nvs_storage_hal.h"

static const char *TAG = "nvs_storage_hal";

static nvs_handle_t handle_hlw8032;

/**
 * @brief nvs_init
 * 
 */
void nvs_init(void)
{
    // Initialize NVS
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        // NVS partition was truncated and needs to be erased
        // Retry nvs_flash_init
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);
}

/**
 * @brief nvs_flash_get
 * 
 * @param namespace_name 
 * @param key 
 * @return int32_t 
 */
int32_t nvs_flash_get(const char *namespace_name, const char *key)
{
    esp_err_t err;
    int32_t hlw_nvs_pf = 0; // value will default to 0, if not set yet in NVS
    // Open
    printf("\n");
    printf("Opening Non-Volatile %s (NVS) handle... ", namespace_name);

    err = nvs_open(namespace_name, NVS_READWRITE, &handle_hlw8032);
    if (err != ESP_OK)
    {
        printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    }
    else
    {
        printf("Done\n");

        // Read
        printf("Reading %s from NVS ... ", key);
        err = nvs_get_i32(handle_hlw8032, key, &hlw_nvs_pf);
        switch (err)
        {
        case ESP_OK:
            printf("Done\n");
            printf("%s = %" PRIu32 "\n", key, hlw_nvs_pf);
            break;
        case ESP_ERR_NVS_NOT_FOUND:
            printf("The value is not initialized yet!\n");
            break;
        default:
            printf("Error (%s) reading!\n", esp_err_to_name(err));
        }

        /*Commit written value.
        After setting any values, nvs_commit() must be called to ensure changes are written
        to flash storage. Implementations may write to storage at other times,
        but this is not guaranteed.*/
        printf("Committing updates in NVS ... ");
        err = nvs_commit(handle_hlw8032);
        printf((err != ESP_OK) ? "Failed!\n" : "Done\n");
        // Close
        nvs_close(handle_hlw8032);
    }
    return hlw_nvs_pf;
}

/**
 * @brief nvs_flash_set
 * 
 * @param namespace_name 
 * @param key 
 * @param input_data 
 */
void nvs_flash_set(const char *namespace_name, const char *key, int32_t input_data)
{
    esp_err_t err;
    // Open
    printf("Opening Non-Volatile %s (NVS) handle... ", namespace_name);
    // nvs_handle_t handle_hlw8032;
    err = nvs_open(namespace_name, NVS_READWRITE, &handle_hlw8032);
    if (err != ESP_OK)
    {
        printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    }
    else
    {
        printf("Done\n");
        // Write
        printf("Updating %s in NVS ... ", key);
        err = nvs_set_i32(handle_hlw8032, key, input_data);
        printf((err != ESP_OK) ? "Failed!\n" : "Done\n");

        /*Commit written value.
        After setting any values, nvs_commit() must be called to ensure changes are written
        to flash storage. Implementations may write to storage at other times,
        but this is not guaranteed.*/
        printf("Committing updates in NVS ... ");
        err = nvs_commit(handle_hlw8032);
        printf((err != ESP_OK) ? "Failed!\n" : "Done\n");

        // Close
        nvs_close(handle_hlw8032);
    }
}
